Elasticsearch 的 Dynamic Field Mapping 注意事項
TLDR
- 正式環境強烈建議使用明確對應 (Explicit Mapping) 以確保效能與儲存效率。
- 動態對應 (Dynamic Mapping) 會導致字串欄位產生
text與keyword雙重索引,造成儲存空間浪費。 - 特殊功能(如地理位置、巢狀物件、自訂分析器)無法透過動態對應自動啟用,必須手動定義。
- 過度依賴動態對應會引發 Mapping Explosion,導致索引欄位數量超過上限 (預設 1000 個)。
- 建議將
dynamic參數設定為false或strict以防止索引結構失控。
動態欄位對應的誤區
在 Elasticsearch 中,雖然動態對應 (Dynamic Mapping) 提供了開發初期的便利性,但在正式環境中卻隱藏著多項風險。
1. 字串型別導致儲存空間膨脹
什麼情況下會遇到這個問題: 當資料庫自動推斷字串欄位型別時。
Elasticsearch 預設會將字串同時儲存為 text 與 keyword 型別。text 用於全文檢索,keyword 用於精確比對與聚合。這種雙重索引機制會導致儲存空間大幅增加。若非必要,應明確定義欄位型別以節省空間。
2. 特殊功能無法自動啟用
什麼情況下會遇到這個問題: 當需要使用地理位置、巢狀結構或自訂分析器時。
動態對應僅能處理基礎型別,無法識別特定需求:
- 地理位置:若未預先定義為
geo_point或geo_shape,系統會將其視為普通object,導致無法使用地理查詢 API。 - 巢狀物件:動態對應會將
nested物件處理為扁平化的object,導致陣列內部的物件無法正確查詢。 - 自訂分析器:動態對應一律使用預設的
standard analyzer,無法套用中文分詞或同義詞處理。
3. Mapping Explosion 的風險
什麼情況下會遇到這個問題: 當資料來源包含大量不固定的欄位名稱(如使用者自訂欄位)時。
若索引中欄位數量過多,會導致記憶體消耗激增。Elasticsearch 預設限制每個索引最多 1000 個欄位,一旦超過此限制,系統將拒絕寫入新文件。
Dynamic Mapping 的型別對應規則
Elasticsearch 根據資料內容自動推斷型別的規則如下:
| JSON 資料型別 | Elasticsearch 型別 ("dynamic":"true") | Elasticsearch 型別 ("dynamic":"runtime") |
|---|---|---|
null | 不新增欄位 | 不新增欄位 |
true 或 false | boolean | boolean |
double | float | double |
long | long | long |
object | object | 不新增欄位 |
array | 取決於陣列中第一個非 null 值 | 取決於陣列中第一個非 null 值 |
通過日期檢測的 string | date | date |
通過數字檢測的 string | float 或 long | double 或 long |
未通過 date 或 numeric 檢測的 string | text 並帶有 .keyword 子欄位 | keyword |
Dynamic 參數的設定選項
為了控管索引結構,建議根據場景調整 dynamic 參數:
true(預設值):新欄位自動加入 mapping。適合開發階段,不建議用於正式環境。runtime:新欄位以 runtime fields 形式存在,不進行索引,查詢時即時計算。適合不常查詢的欄位,節省儲存空間但查詢效能較差。false:忽略新欄位。資料仍會出現在_source中,但無法被搜尋或索引。可有效防止 Mapping Explosion。strict:偵測到新欄位時直接拋出例外並拒絕寫入。這是最嚴格的控制方式,適合結構要求極高的正式環境。
結論
雖然動態對應功能方便,但在正式環境中,建議事先規劃好 Schema 並使用明確對應 (Explicit Mapping)。這能確保儲存空間、查詢效能與功能需求達到最佳平衡,並避免日後因結構變更而必須重新索引 (Reindex) 的高昂成本。
異動歷程
- 2025-10-04 初版文件建立。
